/*
 *      vector2.h 
 * 		(based on Vector2 from "3D Math Primer For Graphics And Game Development")
 *      
 *      2009 Víctor Manuel Ochoa <kanito8a@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#ifndef VECTOR2_H
#define VECTOR2_H

#include <math.h>

class Vector2
{
	public:
		
      	float x;
		float y;
		
		/*
		 * name: constructor
		 * Default constructor leaves vector in an indeterminate state
		 */
      	Vector2() {}
		
		/*
		 * name: constructor
		 * Copy constructor
		 * @param Vector2
		 */
      	Vector2(const Vector2 &a) : x(a.x), y(a.y) {}
      	
		/*
		 * name: constructor
		 * Construct given 2 values
		 * @param float, float, float
		 */
      	Vector2(float nx, float ny) : x(nx), y(ny) {}
		
		/*
		 * name: =
		 * Assignment. We adhere to C convention and return reference to the lvalue
		 * @param Vector2
		 * @return bool
		 */
      	Vector2 &operator =(const Vector2 &a) {
        	x = a.x; y = a.y; 
        	return *this;
      	}
		
		/*
		 * name: ==
		 * Equality
		 * @param Vector2
		 * @return bool
		 */
      	bool operator ==(const Vector2 &a) const 
		{
        	return x==a.x && y==a.y;
      	}
	    
		/*
		 * name: !=
		 * Not Equality
		 * @param Vector2
		 * @return bool
		 */
		bool operator !=(const Vector2 &a) const {
        	return x!=a.x || y!=a.y;
      	}
		
		/*
		 * name: zero
		 * Set the vector to zero
		 * @return void
		 */
		void zero() { x = y = 0.0f; }
		
		/*
		 * name: -
		 * Unary minus returns the negative of the vector
		 * @param Vector2
		 * @return Vector 2
		 */
		Vector2 operator -() const { return Vector2(-x,-y); }
      	
		/*
		 * name: +
		 * Plus operation
		 * @param Vector2
		 * @return Vector 2
		 */
      	Vector2 operator +(const Vector2 &a) const {
        	return Vector2(x + a.x, y + a.y);
      	}
		
		/*
		 * name: -
		 * Minus operation
		 * @param Vector2
		 * @return Vector 2
		 */
      	Vector2 operator -(const Vector2 &a) const {
        	return Vector2(x - a.x, y - a.y);
      	}
      	
		/*
		 * name: *
		 * Multiplication by scalar
		 * @param float
		 * @return Vector 2
		 */
      	Vector2 operator *(float a) const {
        	return Vector2(x*a, y*a);
      	}
		
		/*
		 * name: /
		 * Division by scalar
		 * @param float
		 * @return Vector 2
		 */
      	Vector2 operator /(float a) const {
        	float oneOverA = 1.0f / a; // NOTE: no check for divide by zero here
            return Vector2(x*oneOverA, y*oneOverA);
      	}
		
		/*
		 * name: +
		 * Combined assignment operators to conform to C notation convention
		 * @param Vector2
		 * @return Vector2
		 */
      	Vector2 &operator +=(const Vector2 &a) {
        	x += a.x; y += a.y;
            return *this;
      	}
		
		/*
		 * name: -
		 * Combined assignment operators to conform to C notation convention
		 * @param Vector2
		 * @return Vector2
		 */
      	Vector2 &operator -=(const Vector2 &a) {
             x -= a.x; y -= a.y;
             return *this;
      	}
		
		/*
		 * name: *
		 * Combined assignment operators to conform to C notation convention
		 * @param Vector2
		 * @return Vector2
		 */
      	Vector2 &operator *=(float a) {
        	x *= a; y *= a;
            return *this;
      	}
		
		/*
		 * name: /
		 * Division by scalar
		 * Combined assignment operators to conform to C notation convention
		 * @param float
		 * @return Vector2
		 */
      	Vector2 &operator /=(float a) {
        	float oneOverA = 1.0f / a;
            x *= oneOverA; y *= oneOverA;
            return *this;
      	}
		
		/*
		 * name: normalize
		 * Division by scalar
		 * @return void
		 */
      	void   normalize() {
        	float magSq = x*x + y*y;
            if (magSq > 0.0f) { // check for divide-by-zero
            	float oneOverMag = 1.0f / sqrt(magSq);
                x *= oneOverMag;
                y *= oneOverMag;
            }
      	}
      	
		/*
		 * name: *
		 * Vector dot product.
		 * @param Vector2
		 * @return float
		 */
      	float operator *(const Vector2 &a) const {
        	return x*a.x + y*a.y;
      	}
};

/* *********************************************************************
 * 	Nonmember functions
 * ********************************************************************/

/*
 * name: vectorMag
 * Compute the magnitude of a vector
 * @param Vector2
 * @return float
 */
inline float vectorMag(const Vector2 &a) {
      return sqrt(a.x*a.x + a.y*a.y);
}


/*
 * name: *
 * Scalar on the left multiplication, for symmetry
 * @param float, Vector2
 * @return Vector 2
 */
inline Vector2 operator *(float k, const Vector2 &v) {
      return Vector2(k*v.x, k*v.y);
}

/*
 * name: distance
 * Compute the distance between two points
 * @param Vector2
 * @return float
 */
inline float distance(const Vector2 &a, const Vector2 &b) {
      float dx = a.x - b.x;
      float dy = a.y - b.y;
      return sqrt(dx*dx + dy*dy);
}

/////////////////////////////////////////////////////////////////////////////
// Global variables
/////////////////////////////////////////////////////////////////////////////
// We provide a global zero vector constant
extern const Vector2 kZeroVector2;


#endif /* VECTOR2_H */ 
